home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / gc / GCmark.c < prev    next >
C/C++ Source or Header  |  1991-12-03  |  27KB  |  925 lines

  1. /* begincopyright
  2.   Copyright (c) 1988,1990 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to:
  10.     PCR Coordinator
  11.     Xerox PARC
  12.     3333 Coyote Hill Rd.
  13.     Palo Alto, CA 94304
  14.     
  15.   Parts of this software were derived from code bearing the copyright notice:
  16.   
  17.   Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  18.   This material may be freely distributed, provided this notice is retained.
  19.   This material is provided as is, with no warranty expressed or implied.
  20.   Use at your own risk.
  21.   
  22.   endcopyright */
  23.   
  24. # include <signal.h>
  25. # include <sys/types.h>
  26. # include <sys/times.h>
  27. # include <sys/time.h>
  28. # include <sys/resource.h>
  29. # include <sys/timeb.h>
  30.  
  31. # include "xr/GCPrivate.h"
  32. # include "xr/Threads.h"
  33.  
  34. #define I_HOLD_ML(ml) (((XR_ML)(ml))->ml_holder == XR_currThread)
  35.  
  36. # define COUNT_CACHE_HITS
  37. # undef COUNT_CACHE_HITS
  38.  
  39. /*
  40.  * Derived from the Boehm-Demers collector, with some of C. Hauser's code,
  41.  * and probably some of Mark Weiser's code.
  42.  * Boehm, April 17, 1990 5:34:55 pm PDT
  43.  */
  44.  
  45. /*
  46.  * This file contains the functions:
  47.  *      GC_mark(alignment)
  48.  *      GC_mark_all(b,t,alignment,mark_clean)
  49.  *      GC_get_current_sp()
  50.  */
  51.  
  52. /* Leaving these defined enables output to stderr.  In order of */
  53. /* increasing verbosity:                                        */
  54. #define DEBUG            /* Verbose debugging output */
  55. #undef DEBUG
  56. #define DEBUG2           /* EXTREMELY verbose debugging output */
  57. #undef DEBUG2
  58.  
  59.  
  60. /* Return a rough approximation to the stack pointer.  A hack,  */
  61. /* but it's semi-portable.                                      */
  62. word * GC_get_current_sp()
  63. {
  64.     word x;
  65.     return(&x);
  66. }
  67.  
  68. /*
  69.  *  Proc to see how much page swapping is going on ... returns the 
  70.  *  number of page faults being serviced
  71.  */
  72. unsigned long GC_check_faults()
  73. {
  74.     struct rusage usage;
  75.     
  76.     getrusage(RUSAGE_SELF, &usage);    /* NOT XR_GetRUsage(...)! */
  77.     return(usage.ru_majflt);
  78. }
  79.  
  80.  
  81. /*
  82.  *  Convert the mark stack to bucket form.
  83.  */
  84.  
  85. /*
  86.  * the performance is insensitive to the SEGSIZE and WINDOW
  87.  * for experiments tried this far.
  88.  */ 
  89. #define SEGSIZE 0x100000
  90.    /* size of the segment recorded in each hash bucket */
  91.    
  92. static unsigned long WINDOW = 4;
  93.    /* number of segments inspected together during marking */
  94.    /* not #define'd for ease of experimentation */
  95.    
  96. #define BOUNDARY 0xffffffff 
  97.    /* non-pointer value marking edges of buckets */
  98.    
  99. static unsigned long **alloc;
  100.    /* 
  101.     * all allocation in this file is done below GC_mark_stack_top,
  102.     * by moving alloc to lower addresses.
  103.     */
  104.     
  105. static unsigned long **buckets;
  106.    /*
  107.     * buckets is the address of an array of pointers to hashbuckets.
  108.     * each bucket contains possible pointers into a single SEGSIZE segment
  109.     * of the heap.
  110.     */
  111.     
  112. static int removals;
  113. static int insertions;
  114.    /*
  115.     * insertions-removals is number of candidates remaining to be
  116.     * processed.  Kept separately for statistics gathering.
  117.     */ 
  118.     
  119. static char * GC_my_heaplim;
  120.    /*
  121.     * GC_heaplim when marking started.  Pointers beyond this can safely
  122.     * be ignored, since they must have been created later.  Thus the page
  123.     * in which they were stored will have been dirtied.
  124.     */
  125.     
  126. #ifdef PRINTSTATS
  127.    static unsigned bucketsallocated;
  128. #endif
  129.  
  130.  
  131.     
  132. #define PTRSPERBUCKET 252
  133.    /*
  134.     * no experimentation has been done on the sensitivity of performance to 
  135.     * this value.
  136.     */
  137.     
  138. typedef struct {
  139.   unsigned long *prev;
  140.       /* Points to last pointer slot in prev bucket */
  141.   unsigned long topmark;
  142.   unsigned long *ptrs[PTRSPERBUCKET];
  143.   unsigned long bottommark;
  144.   unsigned long *next;
  145.       /* If in use, points to topmark of next bucket.        */
  146.     /* If free, points to beginning of next free bucket     */
  147. } hashbucket;
  148.   
  149. static hashbucket * bucket_free_list = NIL;
  150.  
  151. hashbucket * allocbucket()
  152. {
  153.     hashbucket * new;
  154.     
  155.     if (bucket_free_list != NIL) {
  156.       new = bucket_free_list;
  157.       bucket_free_list = (hashbucket *) (bucket_free_list -> next);
  158.     } else {
  159.       /* claim space for a bucket from the allocation stack */
  160.         alloc -= (sizeof(hashbucket)/sizeof(unsigned long *));
  161.         new = (hashbucket *)alloc;
  162.     }
  163.  
  164. if((unsigned long) new < 0x10000000) GC_abort("allocbucket");
  165.     return(new);
  166. }
  167.  
  168. void freebucket(b)
  169.     hashbucket *b;
  170. {
  171.     b -> next = (unsigned long *) bucket_free_list;
  172.     bucket_free_list = b;
  173. }
  174.   
  175.  
  176. static unsigned long *newbucket(prevbucket)
  177.    unsigned long *prevbucket;
  178.    /*
  179.     * returns an empty hash bucket pointing back at prevbucket
  180.     */ 
  181. {
  182.    hashbucket *new;
  183.    int i;
  184.    
  185.       new = allocbucket();
  186.      
  187.    /* chain buckets hashing to the same position */ 
  188.       new->prev = prevbucket;
  189.       new->next = NIL;
  190.       
  191.    /* insert boundary marks and initialize contents to empty */
  192.       new->topmark = (new->bottommark = BOUNDARY);
  193.       for (i=0; i < PTRSPERBUCKET; i++) new->ptrs[i] = NIL;
  194.       
  195. #ifdef PRINTSTATS
  196.       ++bucketsallocated;
  197. #endif
  198.    
  199.    /* return a pointer to the topmark slot (making this bucket empty) */
  200.       return (&(new->topmark));
  201. }
  202.   
  203.  
  204. static void insert(p) 
  205.    unsigned long p;
  206.    /*
  207.     * inserts candidate pointer p in the bucket structure
  208.     */
  209. {
  210.    unsigned long **b;
  211.    unsigned long *slotptr;
  212.    struct hblk * h = HBLKPTR(p);
  213.    unsigned long heapoffset = p - (unsigned) GC_heapstart;
  214.    
  215.    if (p >= (unsigned long)GC_my_heaplim) return;
  216.    
  217.    /* Note that the bucket we use corresponds to the actual pointer */
  218.    /* we found, and not necessarily the start address of the heap   */
  219.    /* block.  This may cause the marking process to exhibit         */
  220.    /* slightly less locality.  But it saves some moderately         */
  221.    /* expensive calculation here.                       */
  222.  
  223.    b = buckets+heapoffset/SEGSIZE;
  224.       /* candidate bucket */
  225.      
  226.    slotptr = ++(*b);
  227.       /* candidate position in the hashbucket to record p */
  228.       
  229.    if (*slotptr == BOUNDARY) { /* full: slotptr is pointing
  230.                                   at the bottom mark  */
  231.       slotptr++;
  232.          /* move along to the next field */
  233.       if (*slotptr == (unsigned) NIL) { /* no next bucket yet */
  234.          *slotptr = (unsigned) newbucket(slotptr-2);
  235.             /* create one and chain together */
  236.          };
  237.       
  238.       /* assert: *slotptr == BOUNDARY; (the topmark) */
  239.       slotptr = ((unsigned long *) (*slotptr))+1;
  240.          /* move to the first real slot */ 
  241.       *b = slotptr;
  242.          /* link into hash table */
  243.       };
  244.       
  245.    *slotptr = p;
  246.       /* what we really wanted to do from the start */ 
  247.    insertions++;
  248. }
  249.     
  250.     
  251. static unsigned long remove(b)
  252.    unsigned long **b;
  253.    /*
  254.     * return a candidate pointer from bucket *b points inside, NIL if none
  255.     */
  256. {
  257.    unsigned long *slotptr;
  258.    slotptr = *b;
  259.    if (slotptr == NIL) return (unsigned long)NIL;
  260.                          /* no heap blocks in this bucket */
  261.    if (*slotptr == BOUNDARY) { /* at the topmark */
  262.       if (*(slotptr-1) == (unsigned long)NIL) {
  263.         return (unsigned long)NIL; /* no previous bucket */
  264.       } else {
  265.         hashbucket * ob = (hashbucket *)(slotptr - 1);
  266.         
  267.         slotptr = (unsigned long *) *(slotptr-1); /* move to previous bucket */
  268.         if ((ob -> next) != NIL) {
  269.           /* We leave ob around to avoid lots of allocation around boundary */
  270.           /* We deallocate next bucket, to avoid wasting stack space.        */
  271.             freebucket(ob -> next - 1);
  272.             ob -> next = NIL;
  273.          }
  274.  
  275.       }
  276.    };
  277.    *b = slotptr-1; /* remove an item from the bucket */ 
  278.    removals++;
  279.    return *slotptr; /* return the item */
  280.   
  281.  
  282. static void docandidate();
  283.  
  284. # ifdef USE_HEAP
  285.    --> The careful marking stuff currently assumes that we use the process
  286.        stack for marking
  287. # endif       
  288.  
  289. static void carefulmark(alignment)
  290. int alignment;
  291.    /*
  292.     * for marking when page faults are occurring; 
  293.     */
  294. {
  295.    unsigned nbuckets;
  296.    unsigned long **bucketlim;
  297.  
  298.    register struct obj *p; /* pointer to current object to be marked */
  299.    long heapsize; /* Unlike the global, this includes blocks not administered */
  300.              /* by us.                              */
  301.    unsigned passcount = 0;
  302.   
  303.    struct hblk **blocklim; 
  304.    unsigned blockcount = 0; /* number of heap blocks */
  305.    unsigned startfaults = GC_check_faults();
  306.    unsigned markfaults;
  307.   
  308.    if (GC_mark_stack_top == GC_mark_stack_bottom) return;
  309.    insertions = removals = 0;
  310.    bucketsallocated = 0;
  311.    GC_my_heaplim = GC_heaplim;
  312.    heapsize = GC_my_heaplim - GC_heapstart;
  313.    alloc = (unsigned long **) GC_mark_stack_top;
  314.    bucket_free_list = NIL;
  315.   
  316.  
  317.   {  
  318.     /* construct the empty hash table for candidate pointers */
  319.      unsigned long **b;
  320.      
  321.      nbuckets = (heapsize + SEGSIZE-1) / SEGSIZE;
  322.      bucketlim = alloc;
  323.      buckets = (alloc = alloc-nbuckets); /* claim space for nbuckets */
  324.      for (b = buckets; b < bucketlim; b++) {
  325.         *b = newbucket(NIL);
  326.      };
  327.    }
  328.     
  329.   { /* insert all the initial candidates */
  330.      register word * lim;
  331.      register word * p;
  332.      
  333.      if (sizeof(hashbucket) % sizeof(word) != 0) GC_abort("carefulmark 0");
  334.      while (GC_mark_stack_top < GC_mark_stack_bottom) {
  335.         lim = (word *)(((char *)GC_mark_stack_top) + sizeof (hashbucket));
  336.         p = GC_mark_stack_top;
  337.         if (lim > GC_mark_stack_bottom) {
  338.             while (p < GC_mark_stack_bottom) insert (*p++);
  339.         } else {
  340.             while (p < lim) insert (*p++);
  341.             /* Recycle this section of the mark stack for hash buckets */
  342.               freebucket((hashbucket *)GC_mark_stack_top);
  343.         }
  344.         GC_mark_stack_top = p;
  345.      };
  346.   };
  347.     
  348.   {
  349.      /*
  350.       * Now all the items from the initial stack have been put in buckets;
  351.       * Start processing them;
  352.       */
  353.      
  354.      
  355.      while (insertions != removals) {
  356.         unsigned long **lowlim, **highlim;
  357.                 /* limits of current confined analysis */
  358.         unsigned long **b; /* current hash slot to inspect */
  359.         
  360. #       ifdef PRINTSTATS
  361.           ++passcount;
  362. #       endif
  363.         highlim = buckets+WINDOW;
  364.         if (highlim >= bucketlim) highlim = buckets;
  365.         lowlim = b = buckets;
  366.     
  367.         while (lowlim < bucketlim) {
  368.            p = (struct obj *) remove(b);
  369.            if (p == (struct obj *)NIL) {
  370.                b++;
  371.                if (b == bucketlim) b = buckets;
  372.                if (b == highlim) {
  373.                    while (lowlim < bucketlim && 
  374.                           (*lowlim == NIL
  375.                            || (unsigned) (**lowlim) == BOUNDARY)) {
  376.                        highlim++;
  377.                        if (highlim==bucketlim) highlim=buckets;
  378.                        lowlim++;
  379.                    }; /* while ((lowlim<bucketlim) . . . */
  380.                    b = lowlim;
  381.                 }; /* if (b==highlim) */
  382.            } else /* p != NIL */ { 
  383.               docandidate(p, alignment);
  384.            };
  385.         }; /* while (lowlim < bucketlim) */
  386.      }; /* while (insertions != removals) */
  387. #    ifdef PRINTSTATS
  388.      { 
  389.         markfaults = GC_check_faults() - startfaults;
  390.         GC_markfaults += markfaults;
  391.         GC_printf("Ending mark phase.  Faults: %d, Insertions: %d\n",
  392.                   markfaults, insertions);
  393.         GC_printf("Buckets: %d, Passes: %d\n",bucketsallocated, passcount);
  394.      };
  395. #    endif
  396.   };
  397. } /* carefulmark */
  398.   
  399. static void docandidate(p, alignment)
  400. struct obj *p;
  401. int alignment;
  402. {
  403.    
  404.    long sz;
  405.    long word_no;
  406.    struct hblk * h;
  407.    bool is_atomic;
  408. #  ifdef SEPARATE_HEADERS
  409.      register struct hblkhdr * hhdr;
  410. #  endif
  411. #  ifdef COUNT_CACHE_HITS
  412.      /* Hard to print here, put must be defined for GCcheck_ptr.c */
  413.      long map_cache_hits = 0;
  414.      long map_cache_misses = 0;
  415. #  endif
  416.  
  417.    
  418.     /* Check whether p points to a valid unmarked object.  Continue to the   */
  419.     /* next iteration if not.  Set h to point to the beginning of the block  */
  420.     /* containing p.  Set word_no to the offset of the beginning of the      */
  421.     /* object.  Set sz to the size of the object in words.             */
  422.     /* Set is_atomic and hhdr.                             */
  423. #     define CONTINUE_M return
  424. #     ifdef BLACK_LIST
  425. #     define CONTINUE goto register_bad_c
  426. #     else
  427. #       define CONTINUE return
  428. #     endif
  429. #     include "GCcheck_ptr.c"
  430. #     undef CONTINUE
  431. #     undef CONTINUE_M
  432.    
  433. #  ifdef GATHERSTATS
  434.      GC_my_objects_in_use++;
  435. #  endif
  436.    set_mark_bit(h, word_no);
  437.    if (is_atomic) {
  438.       /* Atomic object */
  439. #     ifdef GATHERSTATS    
  440.       GC_my_atomic_in_use += sz;
  441. #     endif      
  442.       return;
  443.    };
  444.    GC_my_composite_in_use += sz;
  445.    {  
  446.       /* Mark from fields inside the object */
  447.     register struct obj ** q;
  448.     register struct obj * r;
  449.     register long lim;   /* Should be struct obj **, but we're out of */
  450.                  /* A registers on a 68000.                   */
  451.  
  452. #       ifdef INTERIOR_POINTERS
  453.       /* Adjust p, so that it's properly aligned */
  454.         p = ((struct obj *)(((word *)h) + word_no));
  455. #       endif
  456. #       ifdef UNALIGNED
  457.       lim = ((long)(&(p -> obj_component[sz]))) - 3;
  458. #       else
  459.       lim = (long)(&(p -> obj_component[sz]));
  460. #       endif
  461.     for (q = (struct obj **)(&(p -> obj_component[0]));
  462.                     q < (struct obj **)lim;) {
  463.         r = *q;
  464.         if (quicktest(r)) {
  465. #               ifdef DEBUG2
  466.             GC_vprintf("Found plausible nested pointer");
  467.             GC_vprintf(": 0x%X inside 0x%X at 0x%X\n", r, p, q);
  468. #               endif
  469.         insert(r);
  470.         }
  471. #           ifdef UNALIGNED
  472.         q = ((struct obj **)(((long)q)+alignment));
  473. #           else
  474.         q++;
  475. #           endif 
  476.     }
  477.    }; /* mark from fields inside object */
  478. # ifdef BLACK_LIST
  479.     return;
  480.     register_bad_c:
  481.         /* p looks like a pointer, but doesn't point to an    */
  482.         /* objects.                        */
  483.         if ((unsigned long)p
  484.             >= (unsigned long) ((struct hblk *) GC_heapstart + MAP_SIZE)) {
  485.             return;
  486.         }
  487.         GC_add_to_black_list(p);
  488. # endif
  489. } /* docandidate */ 
  490.   
  491.  
  492. static unsigned toomanyfaults = 1000;
  493.  
  494.  
  495. /*
  496.  * Clear mark bits in all allocated heap blocks.
  497.  * Assumes I do not hold GC_allocate_ml, but all reclaim lists are
  498.  * empty.  Thus nobody will look at mark bits while we're
  499.  * running, and hb_busy will not get set.  It may be
  500.  * set when we start, but then we simply wait.
  501.  */
  502. void GC_clear_marks()
  503. {
  504.     register int j;
  505.     register struct hblk **p;
  506.     register struct hblk *q;
  507.  
  508.     if (I_HOLD_ML(&GC_allocate_ml)) {
  509.         XR_Panic("GC_clear_marks 0");
  510.     }
  511.  
  512.     XR_MonitorEntry(&GC_allocate_ml);
  513.     for (q = (struct hblk *) GC_heapstart; ((char*)q) < GC_heaplim; q++)
  514.       if (is_hblk(q)) {
  515.         while (hb_busy(q)) {
  516.             /* There are better ways to synchronize.  But empirically         */
  517.             /* this happens about .2 times during the life of a Cedar world. */
  518.         XR_MonitorExit(&GC_allocate_ml);
  519.             GC_printf("GC_clear_marks waiting for reclaim\n");
  520.             XR_PauseAbortable(1);
  521.         XR_MonitorEntry(&GC_allocate_ml);
  522.         }
  523.  
  524. #       ifdef VISUALIZE
  525.         /* redisplay all marked objects as allocated */
  526.         undisplay_marks(q);
  527. #       endif
  528.         for (j = 0; j < MARK_BITS_SZ; j++) {
  529.         hb_marks(q)[j] = 0;
  530.         }
  531.     }
  532.     XR_MonitorExit(&GC_allocate_ml);
  533.  
  534.     /* In use counts track number of marked words.  Reset private counters. */
  535.     GC_my_atomic_in_use = GC_my_composite_in_use = 0;
  536.     GC_my_objects_in_use = 0;
  537. }
  538.  
  539.  
  540. /* Mark all objects corresponding to pointers between GC_mark_stack_bottom */
  541. /* and GC_mark_stack_top.  Assume that nested pointers are aligned      */
  542. /* on alignment-byte boundaries.                                           */
  543. /* The mark stack is empty when mark returns.                              */
  544. void GC_mark(alignment)
  545. int alignment;
  546. {
  547.   register long sz;
  548.   extern char end, etext;
  549.   register struct obj *p; /* pointer to current object to be marked */
  550.   unsigned startfaults;
  551.   unsigned markfaults;
  552. # ifdef COUNT_CACHE_HITS
  553.       long map_cache_hits = 0;
  554.       long map_cache_misses = 0;
  555. # endif
  556. # ifdef SEPARATE_HEADERS
  557.       register struct hblkhdr * hhdr;
  558. # endif
  559.  
  560.   bool is_atomic;
  561.   /* Register copies of frequently referenced globals */
  562.   /* Referenced primarily from inside macros.         */
  563.     register char * GC_heapstart_reg;
  564.     register word * GC_mark_stack_top_reg;
  565. #   ifdef GATHERSTATS
  566.       register long GC_my_objects_in_use_reg;
  567. #   endif
  568.     
  569.  
  570. # ifdef VISUALIZE
  571.     window_update();
  572. # endif
  573.   
  574.   if ( GC_markCarefully ) {
  575.       carefulmark(alignment);
  576.       return;
  577.   }
  578.   startfaults = GC_check_faults();
  579.   
  580.   /* Set up "global" registers */
  581.     GC_heapstart_reg = GC_heapstart;
  582.     GC_mark_stack_top_reg = GC_mark_stack_top;
  583. #   define GC_mark_stack_top GC_mark_stack_top_reg
  584. #   define GC_heapstart GC_heapstart_reg
  585. #   ifdef GATHERSTATS
  586.       GC_my_objects_in_use_reg = GC_my_objects_in_use;
  587. #   endif
  588.   
  589.   while (GC_mark_stack_top != GC_mark_stack_bottom) {
  590.      register long word_no;
  591.      register struct hblk * h;
  592.  
  593. #    ifdef USE_STACK
  594.     p = (struct obj *)(*GC_mark_stack_top++);
  595. #    else
  596. #     ifdef USE_HEAP
  597.     p = (struct obj *)(*GC_mark_stack_top--);
  598. #     else
  599.     --> fixit <--
  600. #     endif
  601. #    endif
  602.     /* Check whether p points to a valid unmarked object.  Continue to the   */
  603.     /* next iteration if not.  Set h to point to the beginning of the block  */
  604.     /* containing p.  Set word_no to the offset of the beginning of the      */
  605.     /* object.  Set sz to the size of the object in words.             */
  606.     /* Set is_atomic and hhdr.                             */
  607. #     define CONTINUE_M continue
  608. #     ifdef BLACK_LIST
  609. #    define CONTINUE goto register_bad;
  610. #     else
  611. #    define CONTINUE continue
  612. #     endif
  613. #     include "GCcheck_ptr.c"
  614. #     undef CONTINUE
  615. #     undef CONTINUE_M
  616.  
  617.  
  618. #   ifdef DEBUG2
  619.     GC_vprintf("*** set bit for heap %x, word %x\n",h,word_no);
  620. #   endif
  621. #   ifdef SEPARATE_HEADERS
  622.       set_mark_bit_from_hdr(hhdr, word_no);
  623. #   else
  624.       set_mark_bit(h, word_no);
  625. #   endif
  626. #   ifdef VISUALIZE
  627.     displayMark(p, sz);
  628. #   endif
  629. #   ifdef GATHERSTATS
  630.       GC_my_objects_in_use_reg++;
  631. #   endif
  632.     if (is_atomic) {
  633.     /* Atomic object */
  634. #      ifdef GATHERSTATS    
  635.         GC_my_atomic_in_use += sz;
  636. #      endif        
  637.       continue;
  638.     }
  639.     GC_my_composite_in_use += sz;
  640.     {
  641.       /* Mark from fields inside the object */
  642.     register struct obj ** q;
  643.     register struct obj * r;
  644.     register long lim;   /* Should be struct obj **, but we're out of */
  645.                  /* A registers on a 68000.                   */
  646.  
  647. #       ifdef INTERIOR_POINTERS
  648.       /* Adjust p, so that it's properly aligned */
  649.         p = ((struct obj *)(((word *)h) + word_no));
  650. #       endif
  651. #       ifdef UNALIGNED
  652.       lim = ((long)(&(p -> obj_component[sz]))) - 3;
  653. #       else
  654.       lim = (long)(&(p -> obj_component[sz]));
  655. #       endif
  656.     for (q = (struct obj **)(&(p -> obj_component[0]));
  657.                     q < (struct obj **)lim;) {
  658.         r = *q;
  659.         if (quicktest(r)) {
  660. #               ifdef DEBUG2
  661.             GC_vprintf("Found plausible nested pointer");
  662.             GC_vprintf(": 0x%X inside 0x%X at 0x%X\n", r, p, q);
  663. #               endif
  664.         PUSH_MS(((word)r));
  665.         }
  666. #           ifdef UNALIGNED
  667.         q = ((struct obj **)(((long)q)+alignment));
  668. #           else
  669.         q++;
  670. #           endif 
  671.     }
  672.     }
  673.  
  674. #   ifdef VISUALIZE
  675.      /* show marked objects */
  676.       for (i = 0; i < MAP_SIZE; i++) {
  677.     if (hblkmap[i] == HBLK_VALID && GC_dirty_bits[i+offset]) {
  678.         hbp = (struct hblk *)(HBLKSIZE * i + GC_heapstart);
  679.         sz = hb_sz(hbp);
  680.         if (sz < 0) {
  681.         continue;
  682.         }
  683.         if (sz > MAXOBJSZ &&
  684.         mark_bit(hbp, (hbp -> hb_body) - ((word *)(hbp))) ) {
  685.         displayMark(hbp -> hb_body, sz);
  686.         } else {
  687.         /* Small composite objects */
  688.         p = (word *)(hbp->hb_body);
  689.         word_no = p - ((word *)hbp);
  690.         plim = (word *)((((unsigned)hbp) + HBLKSIZE)
  691.              - WORDS_TO_BYTES(sz));
  692.         for (; p <= plim; p += sz, word_no += sz) {
  693.             if (mark_bit(hbp, word_no)) {
  694.             displayMark(p, sz);
  695.             }
  696.         }
  697.         }
  698.     }
  699.       }
  700. #   endif
  701. # ifdef BLACK_LIST
  702.     continue;
  703.     register_bad:
  704.         /* p looks like a pointer, but doesn't point to an    */
  705.         /* objects.                        */
  706.         if ((unsigned long)p
  707.             >= (unsigned long) ((struct hblk *) GC_heapstart + MAP_SIZE)) {
  708.             continue;
  709.         }
  710.         GC_add_to_black_list(p);
  711. # endif
  712.   }
  713.   
  714. # undef GC_heapstart
  715. # undef GC_mark_stack_top
  716.   GC_mark_stack_top = GC_mark_stack_top_reg;
  717. # ifdef GATHERSTATS
  718.     GC_my_objects_in_use = GC_my_objects_in_use_reg;
  719. # endif
  720.   
  721.   markfaults = GC_check_faults()-startfaults;
  722.   GC_markfaults += markfaults;
  723. # ifdef COUNT_CACHE_HITS
  724.     GC_vprintf("%d map cache hits, %d misses\n", 
  725.               map_cache_hits, map_cache_misses);
  726. # endif
  727.  
  728. # ifdef PRINTSTATS
  729.     if (markfaults > 0) {
  730.       GC_vprintf("Generated %d page faults during marking\n", markfaults);
  731.     }
  732. # endif
  733.   }
  734.  
  735. static void GC_mark_all_worker();
  736. static void GC_mark_all_with_coercion_worker();
  737.  
  738.  
  739. /*********************************************************************/
  740. /* Push all possible pointers between b and t onto the mark stack.   */
  741. /* A subsequent call to mark will then                      */
  742. /* mark all locations reachable via pointers located between b and t */
  743. /* b is the first location to be checked. t is one past the last     */
  744. /* location to be checked.                                           */
  745. /* Assume that pointers are aligned on alignment-byte                */
  746. /* boundaries.                                 */
  747. /* Treat clean pages or pages with unknown dirty status according    */
  748. /* to whether mark_clean is ALL_POINTERS, POSSIBLY_DIRTY_POINTERS,   */
  749. /* or DEFINITELY_DIRTY_POINTERS.                     */    
  750. /* If coerce_pointers is TRUE, then try to coerce pointers to         */
  751. /* valid object addresses berfore pushing them.                 */
  752. /* The coercion involves translating an arbitrary pointer to the     */
  753. /* middle of an object into a pointer to the object beginning.         */
  754. /*********************************************************************/
  755. void GC_mark_all(b, t, alignment, mark_clean, coerce_pointers)
  756. word * b;
  757. word * t;
  758. int alignment;
  759. int mark_clean;
  760. bool coerce_pointers;
  761. {
  762. #   ifdef DEBUG
  763.     GC_vprintf("Checking for pointers between 0x%X and 0x%X\n",
  764.         b, t);
  765. #   endif
  766.  
  767.   /* Round b down so it is properly aligned */
  768. #   ifdef UNALIGNED
  769.       if (alignment == 2) {
  770.         b = (word *)(((long) b) & ~1);
  771.       } else if (alignment == 4) {
  772.     b = (word *)(((long) b) & ~3);
  773.       } else if (alignment != 1) {
  774.     GC_abort("Bad alignment parameter to GC_mark_all");
  775.       }
  776. #   else
  777.       b = (word *)(((long) b) & ~3);
  778. #   endif
  779.     if (mark_clean == ALL_POINTERS) {
  780.         if (coerce_pointers) {
  781.             GC_mark_all_with_coercion_worker(b, t, alignment);
  782.         } else {
  783.             GC_mark_all_worker(b, t, alignment);
  784.         }
  785.     } else {
  786.     register unsigned long VD_base_reg
  787.                       = (unsigned long) VD_base;
  788.                       
  789.     if (b >= (word *)VD_base_reg && t <= (word *)GC_heaplim) {
  790.       register unsigned long l = (unsigned long)b;
  791.       register unsigned long u = ((unsigned long)HBLKPTR(l)) + HBLKSIZE;
  792.       register int index;
  793.       
  794.       while (l < (unsigned long)t)  {
  795.         if (u > (unsigned long)t) {
  796.           u = (unsigned long)t;
  797.         }
  798.         index = divHBLKSZ(((unsigned long)l)
  799.                           - ((unsigned long) VD_base_reg));
  800.         if (GC_dirty_bits[index]) {
  801.           if (coerce_pointers) {
  802.               GC_mark_all_with_coercion_worker(l, u, alignment);
  803.           } else {
  804.               GC_mark_all_worker(l, u, alignment);
  805.           }
  806.         }
  807.         l = u;
  808.         u += HBLKSIZE;
  809.       }
  810.     } else if (mark_clean == POSSIBLY_DIRTY_POINTERS) {
  811.       if (coerce_pointers) {
  812.           GC_mark_all_with_coercion_worker(b, t, alignment);
  813.       } else {
  814.           GC_mark_all_worker(b, t, alignment);
  815.       }
  816.     } else if (mark_clean != DEFINITELY_DIRTY_POINTERS) {
  817.       GC_abort("Bad argument to GC_mark_all\n");
  818.     }
  819.     }
  820. }
  821.  
  822.  
  823. static void GC_mark_all_worker(b, t, alignment)
  824. word *b;
  825. word *t;
  826. int alignment;
  827. {
  828.     register word *p;
  829.     register word r;
  830.     register word *lim;
  831.     /* Register copies of frequently referenced globals */
  832.     /* Referenced primarily from inside macros.         */
  833.       register char * GC_heapstart_reg = GC_heapstart;
  834.       register word * GC_mark_stack_top_reg = GC_mark_stack_top;
  835. #   define GC_heapstart GC_heapstart_reg
  836. #   define GC_mark_stack_top GC_mark_stack_top_reg      
  837.  
  838.   /* check all pointers in range and put on mark_stack if quicktest true */
  839.     lim = t - 1 /* longword */;
  840.     for (p = b; ((unsigned) p) <= ((unsigned) lim);) {
  841.         /* Coercion to unsigned in the preceding appears to be necessary */
  842.         /* due to a bug in the 4.2BSD C compiler.                        */
  843.     r = *p;
  844.     if (quicktest(r)) {
  845. #           ifdef DEBUG2
  846.         GC_vprintf("Found plausible pointer: %X\n", r);
  847. #           endif
  848.         PUSH_MS(r);         /* push r onto the mark stack */
  849.     }
  850. #       ifdef UNALIGNED
  851.       p = (word *)(((char *)p) + alignment);
  852. #       else
  853.       p++;
  854. #       endif
  855.     }
  856. #   undef GC_heapstart
  857. #   undef GC_mark_stack_top
  858.     GC_mark_stack_top = GC_mark_stack_top_reg;
  859. }
  860.  
  861.  
  862. static void GC_mark_all_with_coercion_worker(b, t, alignment)
  863. word *b;
  864. word *t;
  865. int alignment;
  866. {
  867.     register word *p;
  868.     register word r;
  869.     register word *lim;
  870.     register struct hblk * h;
  871.     register long sz;
  872.     register long word_no;
  873.     /* Register copies of frequently referenced globals */
  874.     /* Referenced primarily from inside macros.         */
  875.       register char * GC_heapstart_reg = GC_heapstart;
  876.       register char * GC_heaplim_reg = GC_heaplim;
  877.       register word * GC_mark_stack_top_reg = GC_mark_stack_top;
  878. #   define GC_heapstart GC_heapstart_reg
  879. #   define GC_mark_stack_top GC_mark_stack_top_reg      
  880.  
  881.   /* check all pointers in range and try to coerce to object pointers.  */
  882.   /* Put resulting pointers on mark stack.                */
  883.     lim = t - 1 /* longword */;
  884.     for (p = b; ((unsigned) p) <= ((unsigned) lim);) {
  885.     r = *p;
  886.     if (quicktest(r) && (char *)r < GC_heaplim_reg) {
  887. #           ifdef DEBUG2
  888.         GC_vprintf("Found plausible pointer: %X\n", r);
  889. #           endif
  890.         h = HBLKPTR(r);
  891.         if (!is_hblk(h)) {
  892.             char m = get_map(h);
  893.             while (m > 0 && m < 0x7f) {
  894.                 h -= m;
  895.                 m = get_map(h);
  896.             }
  897.             if (!is_hblk(h)) {
  898.                 goto next_p;
  899.             }
  900.             }
  901.             sz = hb_sz(h);
  902.             if (sz < 0) sz = -sz;
  903.             if (sz > MAXOBJSZ) {
  904.                r = ((word)h) + HDR_BYTES;
  905.             } else {
  906.                word_no = WORD_NO(r, h);
  907.                word_no = adjusted_word_no(word_no,sz);
  908.                r = (word)((word *)h + word_no);
  909.             }
  910.         PUSH_MS(r);         /* push r onto the mark stack */
  911.     }
  912.       next_p:
  913.  
  914. #       ifdef UNALIGNED
  915.       p = (word *)(((char *)p) + alignment);
  916. #       else
  917.       p++;
  918. #       endif
  919.     }
  920. #   undef GC_heapstart
  921. #   undef GC_mark_stack_top
  922.     GC_mark_stack_top = GC_mark_stack_top_reg;
  923. }
  924.